import pandas as pd

# 导入文本文件，使用逗号分割
courses_ori = pd.read_csv('courses.txt', sep=',', header=0)
# 预览 DataFrame 前 5 行
courses_ori.head()

i = pd.to_datetime(courses_ori['创建时间'])
i.head()

courses_ts = pd.DataFrame(data=courses_ori.values,
                          columns=courses_ori.columns, index=i)
courses_ts.head()

courses_ts = courses_ts.drop("创建时间", axis=1)
courses_ts.head()

# 按照周次频率进行降采样
courses_ts_W = courses_ts.resample('W').sum()
courses_ts_W.head()

import matplotlib.pyplot as plt

#
plt.figure(figsize=(10, 3))
plt.plot(courses_ts_W.index, courses_ts_W['学习时间'], '-')
plt.xlabel('Time Series')
plt.ylabel("Study Time")
#
# plt.show()

# 绘图库 Seaborn
import seaborn as sns

# 新添加一个序数列，方便绘制散点图
courses_ts_W['id'] = range(0, len(courses_ts_W.index.values))

# 导入文本文件，使用逗号分割
courses_ori = pd.read_csv('courses.txt', sep=',', header=0)
# 预览 DataFrame 前 5 行
courses_ori.head()

i = pd.to_datetime(courses_ori['创建时间'])
i.head()

courses_ts = pd.DataFrame(data=courses_ori.values,
                          columns=courses_ori.columns, index=i)
courses_ts.head()

courses_ts = courses_ts.drop("创建时间", axis=1)
courses_ts.head()

# 按照周次频率进行降采样
courses_ts_W = courses_ts.resample('W').sum()
courses_ts_W.head()

#
plt.figure(figsize=(10, 3))
plt.plot(courses_ts_W.index, courses_ts_W['学习时间'], '-')
plt.xlabel('Time Series')
plt.ylabel("Study Time")

# plt.show()

# 绘图库 Seaborn
import seaborn as sns

courses_ts_W['学习时间'] = courses_ts_W['学习时间'].astype(float)
courses_ts_W['学习人数'] = courses_ts_W['学习人数'].astype(float)
# 重点：这个错误提示是因为在回归直线拟合的过程中，数据的类型不是浮点数，而是对象类型，不符合回归直线的计算要求。因此可以尝试将数据类型转为浮点数类型，可以使用下面的代码进行转换

# 新添加一个序数列，方便绘制散点图
courses_ts_W['id'] = range(0, len(courses_ts_W.index.values))

plt.figure(figsize=(10, 3))
sns.regplot(x="id", y="学习时间", data=courses_ts_W, scatter_kws={
    "s": 10}, order=8, ci=None, truncate=True)
plt.xlabel('Time Series')
plt.ylabel("Study Time")
# plt.show()
# 一开始数据向下凹的厉害，以及最后的翘尾。重新查看数据，可以发现曲线下凹部分是在 2013 年的第二、第三季度新增课程较少。
# 而尾部的上翘，应归结于拟合偏差，可以通过减小 order= 参数的数值，来降低这种偏差。
# 还可以通过设置 x_bins= 参数，绘制出能更加直观反映上升或下降趋势的图像。
sns.regplot(x="id", y="学习人数", data=courses_ts_W, x_bins=10)

plt.xlabel('Time Series')
plt.ylabel("Study Time")
# plt.show()

# 实验学习情况分析
# 每次做单独分析时，最好复制一份整理好的数据，减少对原数据集影响
courses_ts_A = courses_ts.copy()

# 计算平均学习时间并添加列
courses_ts_A['平均学习时间'] = courses_ts_A['学习时间'] / courses_ts_A['学习人数']
courses_ts_A.head()  # 预览
courses_ts_A.sort_values(by='平均学习时间', ascending=False).head()
courses_ts_A.sort_values(by='平均学习时间', ascending=False).tail()

# 添加新列
courses_ts_A['平均学习时间/人数'] = courses_ts_A['平均学习时间'] / courses_ts_A['学习人数']

# 按照比值从小到大排序并显示前 10 条
courses_ts_A.sort_values(by='平均学习时间/人数').head(10)
plt.scatter(courses_ts_A["平均学习时间"], courses_ts_A["学习人数"])
plt.xlabel('Average Study Time')
plt.ylabel("Number of Users")

# 实验课程聚类分析
# 导入 jieba 分词模块
from jieba import analyse

a = []
for i in courses_ts_A['课程名称']:
    # 使用 jieba 分词并使用 TF-IDF 算法抽取两个关键词，仅返回英文、名词、动词、动名词
    a.append(analyse.extract_tags(i, topK=2, withWeight=False,
                                  allowPOS=('eng', 'n', 'vn', 'v')))
keywords = pd.DataFrame(a, columns=['关键词 1', '关键词 2'])
keywords.head()

# 复制一份数据集用于聚类
courses_ts_C = courses_ts_A.copy()
# 重置索引方便数据集拼接
courses_ts_C = courses_ts_C.reset_index()
# 将复制数据集与关键词数据集拼接，并删掉时间列
courses_ts_merged = pd.concat(
    [courses_ts_C, keywords], axis=1).drop("创建时间", axis=1)
# 预览合并后数据集
courses_ts_merged.head()

# 针对关键词进行独热编码处理
onehot = pd.get_dummies(courses_ts_merged[['关键词 1', '关键词 2']])
# 预览
onehot.head()

#527 列的特征已经超过了数据集的 484 行。在这类小规模数据集上，非常不推荐使用过多的特征。
# 所以，我们要针对特征进行降维
from sklearn.decomposition import PCA

# 将特征缩小至 5 维
pca = PCA(n_components=5)
# 返回降维后的值
feature_pca = pca.fit_transform(onehot)

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# 建立模型
score = []
# 依次轮廓系数
for i in range(10):
    model = KMeans(n_clusters=i+2)
    model.fit(feature_pca)
    score.append(silhouette_score(feature_pca, model.labels_))
# 轮廓系数绘图
plt.plot(range(2, 12, 1), score)

# 执行聚类
model = KMeans(n_clusters=6)
model.fit(feature_pca)
# 将类别列添加到数据集中
courses_ts_final = pd.concat(
    [courses_ts_merged, pd.Series(model.labels_, name='类别')], axis=1)
# 依照类别排序并预览数据
courses_ts_final.sort_values(by='类别', ascending=False)
